package com.dubbo.rpc.config;

import com.dubbo.rpc.registry.ServiceRegistry;
import com.dubbo.rpc.aspect.RpcService;
import com.dubbo.rpc.codec.RpcDecoder;
import com.dubbo.rpc.codec.RpcEncoder;
import com.dubbo.rpc.domain.RpcRequest;
import com.dubbo.rpc.domain.RpcResponse;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liuxin
 * @date 2021/10/9 22:57
 */
@Component
public class RpcServer implements ApplicationContextAware, InitializingBean {

    private final Map<String, Object> handleMap = new HashMap<>();

    @Value("${rpc.port}")
    private int rpcPort;

    @Resource
    private ServiceRegistry serviceRegistry;


    /**
     * 服务扫描
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 扫描带有 @RpcService 注解的类
        Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(RpcService.class);

        if (MapUtils.isNotEmpty(beanMap)) {
            for (Object bean : beanMap.values()) {
                RpcService rpcService = bean.getClass().getAnnotation(RpcService.class);
                handleMap.put(rpcService.value().getName(), bean);
            }
        }
    }

    /**
     * 服务注册
     */
    @Override
    public void afterPropertiesSet() {
        NioEventLoopGroup group = new NioEventLoopGroup();
        NioEventLoopGroup childGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            new ServerBootstrap();
            bootstrap.group(group, childGroup);

            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel channel) throws Exception {
                    ChannelPipeline pipeline = channel.pipeline();

                    pipeline.addLast(new RpcDecoder(RpcRequest.class));
                    pipeline.addLast(new RpcEncoder(RpcResponse.class));
                    pipeline.addLast(new RpcServerHandler(handleMap));
                }
            });

            InetAddress localHost = InetAddress.getLocalHost();

            ChannelFuture future = bootstrap.bind(localHost, rpcPort).sync();

            String serviceAddress = localHost.getHostAddress() + ":" + rpcPort;

            for (String interfaceName : handleMap.keySet()) {
                // 服务注册
                serviceRegistry.register(interfaceName, serviceAddress);
            }

            future.channel().closeFuture().sync();
        } catch (Exception e) {
            System.err.println(ExceptionUtils.getStackTrace(e));
        } finally {
            childGroup.shutdownGracefully();
            group.shutdownGracefully();
        }
    }
}
